const PENDING = 'PENDING';
const RESOLVED = 'RESOLVED';
const REJECTED = 'REJECTED';

function resolvePromise(promise2, x, resolve, reject) {
  if (x === promise2) {
    reject(
      new TypeError('TypeError: Chaining cycle detected for promise #<Promise>')
    );
    return;
  }
  let called = false;
  if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
    try {
      let then = x.then;

      if (typeof then === 'function') {
        then.call(
          x,
          (y) => {
            if (called) return;
            called = true;
            resolvePromise(promise2, y, resolve, reject);
          },
          (r) => {
            if (called) return;
            called = true;
            reject(r);
          }
        );
      } else {
        if (called) return;
        called = true;
        resolve(x);
      }
    } catch (error) {
      if (called) return;
      called = true;
      reject(error);
    }
  } else {
    // if (called) return;
    // called = true;
    resolve(x);
  }
}

class Promise {
  constructor(executor) {
    this.status = PENDING;
    this.value = null;
    this.reason = null;
    this.onFulfilledCallbacks = []; // 处理成功的函数list
    this.onRejectedCallbacks = []; // 处理失败的函数list

    try {
      executor(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error);
    }
  }

  resolve(value) {
    if (this.status === PENDING) {
      this.status = RESOLVED;
      this.value = value;
      this.onFulfilledCallbacks.forEach((callback) => callback());
    }
  }
  reject(reason) {
    if (this.status === PENDING) {
      this.status = REJECTED;
      this.reason = reason;
      this.onRejectedCallbacks.forEach((callback) => callback());
    }
  }

  then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== 'function') {
      onFulfilled = (v) => v;
    }

    if (typeof onRejected !== 'function') {
      onRejected = (err) => {
        throw err;
      };
    }
    const promise2 = new Promise((resolve, reject) => {
      if (this.status === RESOLVED) {
        setTimeout(() => {
          try {
            let x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      }

      if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            let x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      }

      if (this.status === PENDING) {
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });

        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
      }
    });

    return promise2;
  }
}

Promise.defer = Promise.deferred = function () {
  let dfd = {};

  dfd.promise = new Promise(function (resolve, reject) {
    dfd.resolve = resolve;
    dfd.reject = reject;
  });

  return dfd;
};

module.exports = Promise;
// 1、executor同步执行, 传入两个函数resolve, reject,需要内部定义两个函数
// 2、resolve和reject都需要传入成功的原因和失败的结果参数
// 3、定义then方法，传入两个函数参数，成功的回调以及失败的回调
// 4、内部有三个状态 pending  ==>  resolve  || pending ==> reject（支持能从pending改变）
// 5、如果是resolve需要执行then的第一个参数(function)
// 6、如果是reject需要执行then后面第二个参数(function)
// 7、onFulfilled || onRejected执行的时候还需要有参数，成功的结果或者失败的原因
// 8、只有在pending的时候状态才能改变
// 9、处理executor内部的错误，调用reject同时传入错误对象进去

// 10、处理异步调用的resolve & 并且能够多次调用then方法（then传进来的方法存起来，状态改变时候再去调用）
// 11.then方法的两个参数必须都是异步执行的，不能再当前执行栈执行

// -------------链式调用------------
// 12、每次then都返回一个promise
// 13、
//      1、如果上一次then里面的参数调用返回的是基本值，使用函数的返回值resolve
//      2、如果代码抛错，使用错误原因reject
//      3、如果是promise，则使用promise执行的结果来处理
//            a、如果x存在then方法就认为是一个promise
//            b、如果x为promise时候，
//                aa. 如果resolve为普通值，下次then也是调用resove处理
//                bb. resolve的值为promise需要继续等待promise完成作为下一次then的结果 (递归调用resolvePromise)
//                cc、 如果失败，直接调用下一次的reject即可
//           c、状态只能改变一次
//      4、如果then执行之后返回的promise，跟处理函数执行返回的promise为同一个值时候，使用reject：TypeError: Chaining cycle detected for promise #<Promise>
//      5、穿透性
